# region 协议实体定义
# # 标识类
# start = '5a'  #起始位：0x5a
# status = 0 #状态字：0-关闭，1-开启
# # 控制类
# ctrl = 0  #控制位：0-自动模式，1-手动模式
# light_swich1 = 0  #灯位1：0-关闭，1-开启
# light_power1 = 0  #灯功率：0-800w,1-1000w,2-1500w
# light_swich2 = 0  #灯位2：0-关闭，1-开启
# light_power2 = 0  #灯功率：0-800w,1-1000w,2-1500w
# light_swich3 = 0  #灯位3：0-关闭，1-开启
# light_power3 = 0  #灯功率：0-800w,1-1000w,2-1500w
# light_swich4 = 0  #灯位4：0-关闭，1-开启
# light_power4 = 0  #灯功率：0-800w,1-1000w,2-1500w
# motorState = 0  #电机状态位：0-停止，1-正转，2-反转
# # 数值类
# temp1 = 0  #温度位：当前温度传感器数值，两字节16进制
# temp2 = 0  #温度位：当前温度传感器数值，两字节16进制
# temp3 = 0  #温度位：当前温度传感器数值，两字节16进制
# pressure = 0  #压力位：当前压力传感器数值，两字节16进制
# meters = 0  #计米器: 当前计米器数值，八字节16进制
# motor = 0  #收盘电机位：一字节16进制，1：正转运行   -2：反转运行  5：自由停机  -7：故障复位；两字节16进制：0-50
# gasPump = 0  #气泵位：一字节16进制，-1：正转运行   2：反转运行  5：自由停机  -7：故障复位；两字节16进制：0-50
# electricity = 0  # 电流
# endregion
import time

import crcmod

from src.common.core import TypeCast


class SerialProtocol:
    def __init__(self):
        self.start = 'a5'

        self.ctrl = 0
        self.light_swich1 = 0
        self.light_power1 = 0
        self.light_swich2 = 0
        self.light_power2 = 0
        self.light_swich3 = 0
        self.light_power3 = 0
        self.light_swich4 = 0
        self.light_power4 = 0
        self.motorState = 0

        self.temp1 = 0
        self.temp2 = 0
        self.temp3 = 0
        self.pressure = 0
        self.meters = 0
        self.motor = 0
        self.motorSpeed = 0
        self.gasPump = 0
        self.gasPumpSpeed = 0
        self.electricity1 = 0
        self.electricity2 = 0
        self.electricity3 = 0
        self.electricity4 = 0

        self.lastMeters = 0
        self.lastMeters2 = 0
        self.lastMeters3 = 0
        self.lastMeters4 = 0

        self.metersTime = 0
        self.lastMetersTime = 0
        self.lastMetersTime2 = 0
        self.lastMetersTime3 = 0
        self.lastMetersTime4 = 0

        self.metersSpeed = 0

        self.lastTemp11 = 0
        self.lastTemp12 = 0
        self.lastTemp13 = 0
        self.lastTemp14 = 0
        self.lastTemp1 = 0

        self.lastTemp21 = 0
        self.lastTemp22 = 0
        self.lastTemp23 = 0
        self.lastTemp24 = 0
        self.lastTemp2 = 0

        self.lastTemp31 = 0
        self.lastTemp32 = 0
        self.lastTemp33 = 0
        self.lastTemp34 = 0
        self.lastTemp3 = 0

        self.crcName = "CrcModbus"

    # region 协议参数相关
    def toHexStr(self):
        """
        协议全部参数转换成16进制字符串
        :return: 16进制字符串
        """
        str = ""
        str += self.start
        str += TypeCast.instance.intToHexStrOnlyValue(self.ctrl)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_swich1)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_power1)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_swich2)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_power2)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_swich3)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_power3)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_swich4)
        str += TypeCast.instance.intToHexStrOnlyValue(self.light_power4)
        str += TypeCast.instance.intToHexStrOnlyValue(self.motorState)

        str += self.toTwoByteHexStr(0)
        str += self.toTwoByteHexStr(0)
        str += self.toTwoByteHexStr(0)
        str += self.toTwoByteHexStr(0)
        # str += self.toEightByteHexStr(int(self.meters * 4294967296))
        if (self.meters == '2114'):
            str += '0000000000000000'
        else:
            str += '1111111111111111'
        str += TypeCast.instance.intToHexStrOnlyValue(self.motor)
        str += self.toTwoByteHexStr(self.motorSpeed * 200)
        str += TypeCast.instance.intToHexStrOnlyValue(self.gasPump)
        str += self.toTwoByteHexStr(self.gasPumpSpeed * 200)
        str += self.toTwoByteHexStr(self.electricity1 * 1000)
        str += self.toTwoByteHexStr(self.electricity2 * 1000)
        str += self.toTwoByteHexStr(self.electricity3 * 1000)
        str += self.toTwoByteHexStr(self.electricity4 * 1000)
        return str

    def useProtocolDict(self, dic):
        self.ctrl = dic['ctrl']
        self.light_swich1 = dic['light_swich1']
        self.light_power1 = dic['light_power1']
        self.light_swich2 = dic['light_swich2']
        self.light_power2 = dic['light_power2']
        self.light_swich3 = dic['light_swich3']
        self.light_power3 = dic['light_power3']
        self.light_swich4 = dic['light_swich4']
        self.light_power4 = dic['light_power4']
        self.motorState = dic['motorState']

        self.lastTemp1 = dic['temp1']
        self.lastTemp2 = dic['temp2']
        self.lastTemp3 = dic['temp3']
        # 815 - 0, 1000 - 0.005   185=0.005
        if dic['pressure'] < 815: dic['pressure'] = 815
        self.pressure = round((dic['pressure']-815)/37000, 3)
        if self.pressure<0: self.pressure=0
        self.meters = dic['meters']
        self.motor = dic['motor']
        self.motorSpeed = dic['motorSpeed']
        self.gasPump = dic['gasPump']
        self.gasPumpSpeed = dic['gasPumpSpeed']
        self.electricity1 = dic['electricity1']
        self.electricity2 = dic['electricity2']
        self.electricity3 = dic['electricity3']
        self.electricity4 = dic['electricity4']

        self.lastMeters4 = self.lastMeters3
        self.lastMeters3 = self.lastMeters2
        self.lastMeters2 = self.lastMeters
        self.lastMeters = self.meters

        self.metersTime = int(time.time())
        self.lastMetersTime4 = self.lastMetersTime3
        self.lastMetersTime3 = self.lastMetersTime2
        self.lastMetersTime2 = self.lastMetersTime
        self.lastMetersTime = self.metersTime

        if (self.lastMetersTime4!=0): self.metersSpeed = round((self.meters - self.lastMeters4) / (self.metersTime-self.lastMetersTime4) * 60, 2)

        self.lastTemp14 = self.lastTemp13
        self.lastTemp13 = self.lastTemp12
        self.lastTemp12 = self.lastTemp11
        self.lastTemp11 = self.lastTemp1
        self.temp1 = int((self.lastTemp1 + self.lastTemp11 + self.lastTemp12 + self.lastTemp13 + self.lastTemp14)/5)

        self.lastTemp24 = self.lastTemp23
        self.lastTemp23 = self.lastTemp22
        self.lastTemp22 = self.lastTemp21
        self.lastTemp21 = self.lastTemp2
        self.temp2 = int((self.lastTemp2 + self.lastTemp21 + self.lastTemp22 + self.lastTemp23 + self.lastTemp24) / 5)

        self.lastTemp34 = self.lastTemp33
        self.lastTemp33 = self.lastTemp32
        self.lastTemp32 = self.lastTemp31
        self.lastTemp31 = self.lastTemp3
        self.temp3 = int((self.lastTemp3 + self.lastTemp31 + self.lastTemp32 + self.lastTemp33 + self.lastTemp34) / 5)


    def hexStrParseDict(self, hexStr):
        """
        16进制字符串转协议参数字典
        :param hexStr: 16进制字节串
        :return: 协议参数字典
        """
        intList = TypeCast.instance.hexByteStrToInts(hexStr)
        dic = {}
        dic['ctrl'] = intList[0]
        dic['light_swich1'] = intList[1]
        dic['light_power1'] = intList[2]
        dic['light_swich2'] = intList[3]
        dic['light_power2'] = intList[4]
        dic['light_swich3'] = intList[5]
        dic['light_power3'] = intList[6]
        dic['light_swich4'] = intList[7]
        dic['light_power4'] = intList[8]
        dic['motorState'] = intList[9]

        dic['temp1'] = int(((intList[10] * 255 + intList[11]) - 819) / 3276 * 500)
        dic['temp2'] = int(((intList[12] * 255 + intList[13]) - 819) / 3276 * 500)
        dic['temp3'] = int(((intList[14] * 255 + intList[15]) - 819) / 3276 * 500)
        # dic['pressure'] = round((((intList[16] * 255 + intList[17]) - 819) / 3276 * 2 + 0.478022)*10000, 4)
        dic['pressure'] = (intList[16] * 255 + intList[17])
        dic['meters'] = 0
        tempStr = '0x'
        for i in intList[18:26]:
            tempStr = tempStr+TypeCast.instance.intToHexStrOnlyValue(i)
        dic['meters'] = int(tempStr, 16)
        if dic['meters'] > 72057594037927935:
            dic['meters'] = dic['meters'] - 18446744073709551616

        dic['meters'] = round((dic['meters'] / 4294967296), 2)
        if (dic['meters']>99999 or dic['meters']< -99999):
            dic['meters'] = self.lastMeters

        dic['motor'] = intList[26]
        dic['motorSpeed'] = int((intList[27] * 255 + intList[28]) / 200)
        dic['gasPump'] = intList[29]
        dic['gasPumpSpeed'] = int((intList[30] * 255 + intList[31]) / 200)
        dic['electricity1'] = round(((intList[32] * 255 + intList[33]) / 1000), 1)
        dic['electricity2'] = round(((intList[34] * 255 + intList[35]) / 1000), 1)
        dic['electricity3'] = round(((intList[36] * 255 + intList[37]) / 1000), 1)
        dic['electricity4'] = round(((intList[38] * 255 + intList[39]) / 1000), 1)
        return dic

    # endregion

    # region 协议用到的类型转换方法
    def toTwoByteHexStr(self, value):
        """
        10进制整数转为两字节16进制字符串
        :param value: 10进制整数
        :return: 两字节16进制字符串
        """
        str = ""
        str += TypeCast.instance.intToHexStrOnlyValue(int(value / 255))
        str += TypeCast.instance.intToHexStrOnlyValue(int(value % 255))

        # str += TypeCast.instance.intToHexStrOnlyValue(int(value / 100))
        # str += TypeCast.instance.intToHexStrOnlyValue(int(value % 100))
        return str

    def toEightByteHexStr(self, value):
        str1 = hex(value).replace("0x", "")
        str2 = "0" * (16-len(str1))
        return str2 + str1

    def twoByteHexStrToInt(self, hexStr):
        """
        两字节16进制字符串转为10进制整数
        :param hexStr: 两字节16进制字符串
        :return: 10进制整数
        """
        value = 0
        value += int(hexStr[:4], 16) * 255
        value += int(hexStr[4:8], 16)
        return value

    def toFourLenHexStr(self, value):
        """
        10进制整数转为4长度的16进制字符串
        :param value: 10进制整数(0-255)
        :return: 4长度的16进制字符串
        """
        if value > 255: value = 255
        if value < 0: value = 0
        if value > 15:
            return hex(value)
        else:
            return f"0x0{hex(value)[-1]}"

    # endregion

    # region 生成协议和解析协议的方法
    def makeProtoData(self):
        hexStr = self.toHexStr()  # 将协议内容转为不带标识的16进制字符串
        hexByteStr = TypeCast.instance.hexStrOnlyValueToHexByteStr(hexStr)  # 将不带标识的16进制字符串转为16进制字节串
        # print(hexByteStr, len(hexByteStr))
        crcHexByteStr = TypeCast.instance.hexStrOnlyValueToHexByteStr(
            TypeCast.instance.intToHexStrOnlyValue(
                crcmod.predefined.mkCrcFun(self.crcName)
                (hexByteStr)))  # 根据16进制字节串生成crc校验码(int)，然后转为不带标识的16进制字符串，最后转为16进制字节串
        crcHexByteStr = crcHexByteStr[1:2] + crcHexByteStr[0:1]
        return hexByteStr + crcHexByteStr

    def parseProtoData(self, protoData):
        protoData = str(protoData)[2: 88]
        # print(protoData)
        if protoData[0:2] == 'a5':
            hexStrOnlyValue = protoData[0:84]
            # print(hexStrOnlyValue)
            crcHexStrOnlyValue = protoData[84:88]
            # print(crcHexStrOnlyValue)
            hexByteStr = TypeCast.instance.hexStrOnlyValueToHexByteStr(hexStrOnlyValue)  # 将不带标识的16进制字符串转为16进制字节串
            newCrcHexStrOnlyValue = TypeCast.instance.intToHexStrOnlyValue(
                crcmod.predefined.mkCrcFun(self.crcName)
                (hexByteStr))  # 根据16进制字节串生成crc校验码(int)，然后转为不带标识的16进制字符串
            newCrcHexStrOnlyValue = newCrcHexStrOnlyValue[2:4] + newCrcHexStrOnlyValue[0:2]
            # print(hexByteStr)
            # print(crcHexStrOnlyValue, newCrcHexStrOnlyValue)
            if crcHexStrOnlyValue == newCrcHexStrOnlyValue:
                dic = self.hexStrParseDict(hexByteStr[1:])
                self.useProtocolDict(dic)

    # endregion

    # region 静态方法
    def toDict(self):
        return {'ctrl': self.ctrl, 'light_swich1': self.light_swich1, 'light_swich2': self.light_swich2,
                'light_swich3': self.light_swich3, 'light_swich4': self.light_swich4,
                'light_power1': self.light_power1, 'light_power2': self.light_power2,
                'light_power3': self.light_power3, 'light_power4': self.light_power4,
                'motorState': self.motorState, 'temp1': self.temp1, 'temp2': self.temp2,
                'temp3': self.temp3, 'pressure': self.pressure, 'meters': self.meters,
                'gasPump': self.gasPump, 'gasPumpSpeed': self.gasPumpSpeed,
                'motor': self.motor, 'motorSpeed': self.motorSpeed,
                'electricity1': self.electricity1, 'electricity2': self.electricity2,
                'electricity3': self.electricity3, 'electricity4': self.electricity4,
                'metersSpeed': self.metersSpeed
                }

    def toString(self):
        return f'{{"ctrl": {self.ctrl}, "light_swich1": {self.light_swich1}, "light_swich2": {self.light_swich2},' \
               f' "light_swich3": {self.light_swich3}, "light_swich4": {self.light_swich4}, ' \
               f' "light_power1": {self.light_power1}, "light_power2": {self.light_power2}, ' \
               f' "light_power3": {self.light_power3}, "light_power4": {self.light_power4}, ' \
               f' "motorState": {self.motorState}, "temp1": {self.temp1}, "temp2": {self.temp2},' \
               f' "temp3": {self.temp3}, "pressure": {self.pressure}, "meters": {self.meters}, ' \
               f' "gasPump": {self.gasPump}, "gasPumpSpeed": {self.gasPumpSpeed}, ' \
               f' "motor": {self.motor}, "motorSpeed": {self.motorSpeed},' \
               f' "electricity1": {self.electricity1}, "electricity2": {self.electricity2},' \
               f' "electricity3": {self.electricity3}, "electricity4": {self.electricity4},' \
               f' "metersSpeed": {self.metersSpeed}' \
               f'}}'
    # f'"gasPump": {self.gasPump},' \
        # endregion


instance = SerialProtocol()


def clone():
    proto = SerialProtocol()
    proto.useProtocolDict(instance.toDict())
    return proto


# region 测试方法
if __name__ == '__main__':
    dic = {'ctrl': 1, 'light1': 10, 'light2': 100, 'light3': 105, 'light4': 241,
           'motorState': 231, 'temp': 2587, 'pressure': 123, 'meters': 250, 'gasPump': 1257, 'motor': 3258}
    instance.useProtocolDict(dic)
    # hexStr = instance.toHexStr()
    # hexByteStr = TypeCast.instance.hexStrOnlyValueToHexByteStr(hexStr)
    # print(hexStr, len(hexStr))
    # hexStrs = TypeCast.instance.hexByteStrToHexStrs(hexByteStr)
    #
    # print(hexStrs)
    # crcHexStr = TypeCast.instance.intToHexStrOnlyValue(crcmod.predefined.mkCrcFun('Crc16Usb')(hexByteStr))
    # print(hexStr+crcHexStr)
    # byteStrData = TypeCast.instance.hexStrOnlyValueToHexByteStr(hexStr+crcHexStr)
    # print(byteStrData)

    # print(instance.hexStrParseDict(instance.toHexStr()))
    #
    # print(bytes.fromhex(instance.toHexStr()))
    # print(instance.makeProtoData())

# endregion
